import {celebrate, Joi} from "celebrate";
import {withLock} from "easylock";
import {Request, Router,} from 'express'
import {AddressModel} from "../database/models/address";
import {findAreaByPcaCode, isValidatePcaCode, isValidatePcasCode, pcasByCode} from "../pcas/pca2pacs";
import {InternalError} from "./error";
import {Response, withUser} from "./middlewareType";
import {jwtAuthMiddleware} from "./passort";


const addressRouter = Router()

export default addressRouter

addressRouter.get('/',
  jwtAuthMiddleware,
  async (req: Request & withUser, res) => {

    const addresses = await AddressModel.find({player: req.user.id})

    res.json({
      ok: true, data: {addresses}
    })
  }
)

addressRouter.get('/streets',
  celebrate({
    query: {
      pca: Joi.string().required().length(6)
    }
  }),
  (req, res, next) => {

    if (isValidatePcaCode(req.query.pca)) {
      next()
    } else {
      res.json({
        ok: false, error: "BAD_PCA_CODE",
        msg: "错误的PCA码"
      })
    }
  },
  async (req, res) => {
    const area = findAreaByPcaCode(req.query.pca)
    res.json({
      ok: true, data: {streets: area.children}
    })
  }
)

const isValidatePCAS = (codeFrom: (Request) => string = (req) => req.body.pcas) => {

  return (req, res, next) => {

    if (isValidatePcasCode(codeFrom(req))) {
      return next()
    }

    return res.json({
      ok: false, error: 'BAD_PCAS', msg: '地区码错误'
    })
  }

}


addressRouter.post('/',
  jwtAuthMiddleware,
  celebrate({
    body: Joi.object().keys({
      pcas: Joi.string().required().length(9).regex(/\d+/),
      address: Joi.string().required(),
      phone: Joi.string().required(),
      receiver: Joi.string().required(),
      alias: Joi.string().optional().max(5),
      'default': Joi.boolean().optional().default(false)
    })
  }), isValidatePCAS(),
  async (req: Request & withUser, res) => {
    const areas = pcasByCode(req.body.pcas)

    try {
      await withLock(req.user.id, async () => {

        const n = await AddressModel.count({player: req.user.id})

        if (n > 5) {
          return res.json({
            ok: false,
            error: 'TOO_MANY_ADDRESS',
            msg: '每个玩家只能创建5个地址'
          })
        }
        const isDefault = n === 0 || req.body.default

        if (isDefault) {
          await AddressModel.updateMany({player: req.user.id}, {
            $set: {
              default: false
            }
          })
        }

        const address = await AddressModel.create({
          player: req.user.id,
          pcasCode: req.body.pcas,
          province: areas[0].name,
          city: areas[1].name,
          area: areas[2].name,
          street: areas[3].name,
          detail: req.body.address,
          phone: req.body.phone,
          receiver: req.body.receiver,
          alias: req.body.alias,
          'default': isDefault
        })

        res.json({
          ok: true,
          data: {address}
        })
      })
    } catch (e) {
      res.json({
        ok: false,
        error: e.message,
        msg: '服务器错误'
      })
    }
  }
)

addressRouter.patch('/:addressId',
  jwtAuthMiddleware,
  celebrate({
    body: Joi.object().keys({
      pcas: Joi.string().required().length(9).regex(/\d+/),
      address: Joi.string().required(),
      phone: Joi.string().required(),
      receiver: Joi.string().required(),
      alias: Joi.string().optional().max(5),
    })
  }),
  isValidatePCAS(),
  async (req: Request & withUser, res: Response) => {
    const areas = pcasByCode(req.body.pcas)
    try {
      const add = await AddressModel.find({
        player: req.user._id, _id: req.params.addressId
      })
      if (!add) throw InternalError('NO_SUCH_ADDRESS')

      const updatedAddress = {
        player: req.user.id,
        pcasCode: req.body.pcas,
        province: areas[0].name,
        city: areas[1].name,
        area: areas[2].name,
        street: areas[3].name,
        detail: req.body.address,
        phone: req.body.phone,
        receiver: req.body.receiver,
        alias: req.body.alias,
      }
      const newAdd = await AddressModel.findByIdAndUpdate({_id: req.params.addressId}, updatedAddress, {new: true})

      res.json({ok: true, data: {address: newAdd}})
    } catch (e) {
      res.error(e)
    }
  }
)

addressRouter.delete('/:addressId',
  jwtAuthMiddleware,
  async (req: Request & withUser, res) => {
    try {
      await AddressModel.deleteOne({
        _id: req.params.addressId,
        player: req.user.id,
      })
    } finally {
      res.json({ok: true})
    }
  })

addressRouter.put('/:addressId/default',
  jwtAuthMiddleware,
  async (req: Request & withUser, res: Response) => {
    try {
      const add = await AddressModel.findOne({
        _id: req.params.addressId,
        player: req.user.id,
      })

      if (add) {
        await AddressModel.updateMany({
          player: req.user.id,
          default: true
        }, {$set: {default: false}})

        add.default = true
        await add.save()
        res.json({ok: true, data: {address: add}})
      } else {
        throw  InternalError('NO_SUCH_ADDRESS')
      }
    } catch (e) {
      res.error(e)
    }
  })
